#include"../include/file_descriptor.h" 
#include"../include/main_header.h"
#include"../include/block.h"
#include"../include/hashtab.h"
#include"../include/bst.h"
#include"../include/narray.h"
#include"../include/free_list.h"
#include"../include/trie.h"
#include"../include/vfs_errorcodes.h" 
#include<stdio.h>
#include<string.h>

void create_vfs(char *vfs_label,int vfs_size)
{
struct block b;

strcpy(m.vfs_label,vfs_label);

m.vfs_size = vfs_size*1024;
//initializing meta header attributes
m.max_descriptors=(m.vfs_size/BLOCK_SIZE);
m.fd_used=0;
m.free_address=(sizeof(struct main_header))+BLOCK_SIZE;
m.root_address=(sizeof(struct main_header));
m.root_size=1;//in terms of blocks
m.root_descriptors=0;


//creating VFS on disk
fp=fopen(m.vfs_label,"wb");


/////////////////cannot create data file error/////////////////////
if(fp == NULL)
{
	
	printf("%s%s\n", "createvfs_FAILURE ",ERR_VFS_CREATE_02);         //can not creat data file
	return ;
}


fseek(fp,m.vfs_size,0);
putc(0,fp);	


//writing meta header
rewind(fp);
fwrite(&m,sizeof(m),1,fp);

//creating root block at the location following the meta header
b.next=0xFFFF;
fwrite(&b,sizeof(struct block),1,fp);

//creating blocks
create_blocks();
fclose(fp);       //glibc

printf("%s\n", "createvfs_SUCCESS");
}

void mount_vfs(char *vfs_label)
{
///////////vfs already mounted error///////////////////////
if(vfs_mounted)
{

	printf("%s%s\n", "mountvfs_FAILURE ",ERR_VFS_MOUNT_03);   //vfs already mounted
	return;
}


int re_type;
initializeHashTable(hashTable);
createroot();
avl_root = NULL;
//trieHead = NULL;
//define_free_list_size();
//initialize_free_list();

initailizeFDList();

char nary_path[100]={'/','\0'};
//opening the VFS file
//printf("\nEnter label of the VFS\n");
//scanf("%s",m.vfs_label);

strcpy(m.vfs_label,vfs_label);
fp=fopen(m.vfs_label,"rb+");


//reading the meta header
re_type = fread(&m,sizeof(m),1,fp);

define_free_list_size();
initialize_free_list();

////can not read from file error
if(re_type == 0)
{
	printf("%s%s\n", "mountvfs_FAILURE ", ERR_VFS_MOUNT_02);
	return;
}

create_free_list();

fseek(fp,sizeof(struct main_header),0);

//printf("%d...%d",m.root_descriptors,BLOCK_DESCRIPTORS);
//printf("\npath=%d",strlen(nary_path));
print_narry(m.root_descriptors, nary_path);
//traverseFDList();
mountHashTable(FDList, hashTable);
mountBST(FDList);
//mountTries(FDList, trieHead);
//inorderBST(bst_root);
mountnarray(FDList);

struct file_descriptor_list *temp = FDList->next;
while(temp != NULL)
	{	
		//printf("\naddress:%ld descriptors: %d",temp->fdescriptor.descriptor_address,temp->fdescriptor.dir_descriptors);
		//printf("\nram address:%u",&(temp->fdescriptor));
		//printf("\n%s",temp->fdescriptor.file_name);
		//fseek(fp, temp->fdescriptor.descriptor_address, 0);
		//fwrite(&(temp->fdescriptor), sizeof(struct file_descriptor), 1, fp);
		temp = temp->next;
	}
//fclose(fp);
	printf("%s\n", "mountvfs_SUCCESS");
	vfs_mounted = 1;
}
void unmount_vfs(char *vfs_label)
{
	struct node  *n;
	int i,re_type;
	rewind(fp);
	struct file_descriptor_list *temp = FDList->next;
	struct block b;
	while(temp != NULL)
	{	
		//printf("\naddress:%ld descriptors: %d",temp->fdescriptor.descriptor_address,temp->fdescriptor.dir_descriptors);
		//printf("\nram address:%u",&(temp->fdescriptor));
		//printf("\n%s",temp->fdescriptor.file_name);
		fseek(fp, temp->fdescriptor.descriptor_address, 0);
		re_type = fwrite(&(temp->fdescriptor), sizeof(struct file_descriptor), 1, fp);
		if (re_type == 0)
		{
			printf("%s%s\n", "unmountvfs_FAILURE ", ERR_VFS_UNMOUNT_02);
			return ;
		}
		temp = temp->next;
	}
	//n=Searchnarray("/f1");
	//printf("\naddress:%u",(n->nodefile_descriptor));
	fseek(fp, sizeof(struct main_header), 0);
	for(i=0; i<(FREE_LIST_SIZE)/sizeof(unsigned long int); i++)
	{
		fread(&b, sizeof(struct block), 1, fp);
		if(fl.list[i] == 0xFFFF)
			b.next = fl.list[i];
		else
			b.next = blockToabsolute(fl.list[i]);
		fseek(fp, -sizeof(struct block), 1);
		fwrite(&b, sizeof(struct block), 1, fp);
	}
	m.free_address = blockToabsolute(fl.first_free);
	rewind(fp);
	fwrite(&m, sizeof(struct main_header), 1, fp);
	fclose(fp);
	printf("%s\n", "unmountvfs_SUCCESS");
	vfs_mounted = 0;
}
void test_disk()
{
struct block b;
struct file_descriptor f;
int i = 0;
unsigned long int start=1;
fp=fopen("test","rb+");
//printf("\n");
while(fl.list[start]!=0xFFFF)
{
	
	fseek(fp,(start*68)+40,0);
	fread(&b,sizeof(struct block),1,fp);
/*	for(i=0;i<64;i++)
	{
		printf("%c",b.data[i]);	
	}	
*/	
	//printf("%s",b.data);
	start = fl.list[start];
}
	fseek(fp,(start*68)+40,0);
	fread(&b,sizeof(struct block),1,fp);
/*	for(i=0;i<64;i++)
	{
		printf("%c",b.data[i]);	
	}		
*/	//printf("%s",b.data);
	//printf("\nsize of data %d and last data is %c \n",sizeof(b.data),b.data[63]);
/*	
fseek(fp,40,0);
fread(&f,sizeof(struct file_descriptor),1,fp);
print_descriptor(f);


fseek(fp,108,0);
fread(&f,sizeof(struct file_descriptor),1,fp);
print_descriptor(f);*/
fclose(fp);
}
void print_vfs_details()
{
printf("\nmeta header size is %d\n",sizeof(struct main_header));
printf("\nVFS label:%s",m.vfs_label);
printf("\nVFS size:%ld",m.vfs_size);
printf("\nmax descrriptors:%d",m.max_descriptors);
printf("\nused descriptors:%d\n",m.fd_used);
printf("\nfirst free block address:%ld\n",m.free_address);
printf("\nroot directory address:%ld\n",m.root_address);

//print starting addressess of all blocks
//get_addresses();// in block.c
}

//save changes made int he meta header
void update_main_header()
{
//fp=fopen("test","rb+");
rewind(fp);
fwrite(&m,sizeof(struct main_header),1,fp);
//fclose(fp);
}

int check_slash( char *name)
{
	int i;
	for(i = 0 ; i < strlen(name);i++)
	{
		if(name[i] == '/')
			return 1;
	}
	return 0;
}
int create_vfs_validate(char *pathv , int size)

{
	int success = 1;
	FILE *ptr;
	if((strlen(pathv) == 0) )
	{
		success = -1;
		printf("%s%s\n", "createvfs_FAILURE ", ERR_VFS_CREATE_00);    //insufficient argument
	}
	else if( (ptr = fopen(pathv,"rb")) != NULL )
	{
		success = -1;
		printf("%s%s\n", "createvfs_FAILURE ", ERR_VFS_CREATE_01);  //data file already exists
		fclose(ptr);	     //glibc
	}
	else if(checkslash(pathv) == -1)
	{
		success = -1;
		printf("%s%s\n", "createvfs_FAILURE ", ERR_VFS_CREATE_03);   //invalid char
	}
	else if(size<=0 || size>1024)
	{
		success = -1;
		printf("%s%s\n", "createvfs_FAILURE ", ERR_VFS_CREATE_04);   // invalid size	
	}
	else if(strlen(pathv) > 30)
	{
		success = -1;
		printf("%s%s\n", "createvfs_FAILURE ", ERR_VFS_CREATE_05);   // lable too large	
	}

	return success;
}
int mount_vfs_validate(char *pathv)
{
	int success = 1;
	FILE *ptr;
	if((strlen(pathv) == 0) )
	{
		success = -1;
		printf("%s%s\n", "mountvfs_FAILURE ", ERR_VFS_MOUNT_00);    //insufficient argument
		return success;
	}
	if((ptr = fopen(pathv,"rb")) == NULL )
	{
		success = -1;
		printf("%s%s\n", "mountvfs_FAILURE ", ERR_VFS_MOUNT_01);  //data file  not found
		return success;
	}
	else
	{
		fclose(ptr);      //glibc
		return success;
	}
	return success;
}
int unmount_vfs_validate(char *pathv)
{
	int success = 1;
//	printf("%s\n", pathv);
//	printf("%d\n", vfs_mounted);

	if((strlen(pathv) == 0) )
	{
		success = -1;
		printf("%s%s\n", "unmountvfs_FAILURE ", ERR_VFS_UNMOUNT_00);    //insufficient argument
	}
	else if(vfs_mounted == 0)
	{
		success = -1;
		printf("%s%s\n", "unmountvfs_FAILURE ", ERR_VFS_UNMOUNT_03);    //vfs not mounted	
	}
	else if((vfs_mounted == 1) && (strcmp(m.vfs_label,pathv)) )
	{
		success = -1;
		printf("%s%s\n", "unmountvfs_FAILURE ", ERR_VFS_UNMOUNT_01);    // Data file not found
	}

	return success;
}
